%%%-------------------------------------------------------------------
%%% @author mirahs(2892727493@qq.com)
%%% @doc
%%%     角色事件触发
%%% @end
%%%-------------------------------------------------------------------
-module(role_event).

-export([
    init/0
    ,fire/2
    ,fire/3

    ,add/3
    ,del/3
    ,get/2
]).

-include("common.hrl").
-include("role.hrl").
-include("event.hrl").


%%%===================================================================
%%% API functions
%%%===================================================================

init() ->
    % 索引从 0 开始，程序从 1 开始，所以数量要 +1
    #event{next_id = 1, data = array:new(?event_max + 1, [{default, []}])}.

%% @spec fire(Role, EventType, EventParas) -> NewRole
%% Role = NewRole = #role{}
%% EventType = integer()
%% EventParas = term()
%% 触发事件
fire(Role, EventType) ->
    fire(Role, EventType, []).

fire(Role = #role{event = undefined}, EventType, EventParas) ->
    do_callback_def(Role, EventType, EventParas);
fire(Role = #role{event = #event{data = Tgs}}, EventType, EventParas) ->
    %?DEBUG("[~s]触发事件: [type=~w][paras=~w]", [_Name, EventType, EventParas]),
    NewRole = do_callback_def(Role, EventType, EventParas), %% 默认触发器
    Triggers = array:get(EventType, Tgs),
    do_callback(EventType, Triggers, NewRole, EventParas).


%% @spec add(Type, T, Mfa) -> {ok, Id, NewTrigger}
%% Type = integer()
%% T = #trigger{}
%% NewTrigger = #trigger{}
%% Mfa = mfa()
%% Id = integer()
%% @doc 添加触发器
add(Type, T = #event{next_id = Id, data = Tgs}, {M, F, A}) ->
    L = array:get(Type, Tgs),
    NewTgs = array:set(Type, [{Id, {M, F, A}} | L], Tgs),
    NT = T#event{next_id = Id + 1, data = NewTgs},
    %?DEBUG("增加事件监听: [type=~w]", [Type]),
    {ok, Id, NT}.

%% @spec del(Type, Trigger, Id) -> {ok, NewTrigger}
%% Type = integer()
%% trigger = #trigger{}
%% NewTrigger = #trigger{}
%% Id = integer()
%% @doc 删除触发器
del(Type, T = #event{data = Tgs}, Id) ->
    L = array:get(Type, Tgs),
    NL = lists:keydelete(Id, 1, L),
    NT = T#event{data = array:set(Type, NL, Tgs)},
    %?DEBUG("删除事件监听: [type=~w]", [Type]),
    {ok, NT}.

%% @spec get(Type, T) -> List
%% Type = integer()
%% T = #trigger{}
%% List = []
%% 获取监听了指定类型的触发器
get(Type, _T = #event{data = Tgs}) ->
    L = array:get(Type, Tgs),
    L.

%% @spec do_callback(Label, FunList, Role, Args) -> NewRole
%% Label = atom()
%% FunList = list()
%% Role = #role{}
%% Args = list()
%% @doc 执行相应类型触发器回调
do_callback(_Type, [], Role, _Params) -> Role;
do_callback(Type, [{Id, {M, F, A}} | T], Role, Params) ->
    %?DEBUG("任务回调 label ~w, m ~w, f ~w, a ~w, args ~w", [Label, M, F, A, Args]),
    case catch erlang:apply(M, F, [Role, #event_data{id = Id, params = Params, args = A, type = Type}]) of
        ok ->
            do_callback(Type, T, Role, Params);
        {ok, NewRole} when is_record(NewRole, role) ->
            do_callback(Type, T, NewRole, Params);
        Else ->
            ?ERR("角色[~s]调用[~w]触发器中的{~w, ~w, ~w}时发生错误:~w", [Role#role.name, Type, M, F, A, Else]),
            do_callback(Type, T, Role, Params)
    end.

%% 回调默认触发器
do_callback_def(Role, Type, EventParas) ->
    Events = role_event_handler:get(Type),
    do_callback_def(Role, Type, EventParas, Events).

do_callback_def(Role, _Type, _Paras, []) ->
    Role;
do_callback_def(Role, Type, Paras, [{M, F, A} | T]) ->
    case catch erlang:apply(M, F, [Role, #event_data{id = 0, params = Paras, args = A, type = Type}]) of
        ok ->
            do_callback_def(Role, Type, Paras, T);
        {ok, NewRole} ->
            do_callback_def(NewRole, Type, Paras, T);
        Else ->
            ?ERR("角色[~s]调用[~w]默认触发器中的{~w, ~w, ~w}时发生错误:~n~p", [Role#role.name, Type, M, F, A, Else]),
            do_callback_def(Role, Type, Paras, T)
    end.
